package samplejava.compiler;

import java.util.ArrayList;

public class EntryTS {
	public static final int NIL = -1; // entrada nula, error
	public static final int UDEC = 0; /* not declared */
	public static final int FUNC = 1; /* fuction */
	public static final int UFUNC = 2; /* undefined function */
	public static final int VAR = 3; /* declared variable */
	public static final int PARAM = 4; /* undeclared parameter */
	public static final int PARAM_REF = 5;
	
	//public static final int TYPE = 5; //int o long
	
	private ETipo tipo; //para saber si es int o long (si es funcion tipo de retorno)
	
	private String name; // lexema
	private int kind; // tipo de simbolo. esto por ahora esta muy simplificado
	private int blockLevel; // profundidad de nivel
	private int offset; //desplazamiento relativo
	//private EntryTS next; /* next entry */
	
	private static String[] kindStrings = { "UDEC" , "FUNC", "UFUNC", "VAR", "PARAM", "PARAM_REF" };
	
		
	//private void setTipo()
	
	public static String getKindStr(int id) {
		return kindStrings[id];
	}
	
	public EntryTS() {
		this.tipo = new ETipo_Int(); //por defecto
		this.name = " ";
		this.kind = NIL; //nula, error.
		this.blockLevel = 1;
		this.offset = 0;
		
	}
	
	public EntryTS(String name, int kind, int blockLevel) {
		this.tipo = new ETipo_Int(); //por defecto
		this.name = name;
		this.kind = kind;
		this.blockLevel = blockLevel;
		this.offset = 0;
		
	}
	
	public EntryTS(String name, int kind, int blockLevel, long value, int tipo, int offset) {
		this.name = name;
		this.kind = kind;
		this.blockLevel = blockLevel;
		this.offset = offset;
		
		switch (tipo) {
			case Tipos.INT: this.tipo = new ETipo_Int(value); break;
			case Tipos.LONG: this.tipo = new ETipo_Long(value); break;
			case Tipos.FLOAT: this.tipo = new ETipo_Float(value); break;
			case Tipos.POINTER: this.tipo = new ETipo_Pointer(); break;
			default: this.tipo = new ETipo_Int(); //por poner algo xD
		} 
		
	}
	
	public EntryTS(String name, int kind, int blockLevel, long value, int tipo) {
		this(name, kind, blockLevel, value, tipo, 0); //offset = 0
	}
	
	/*public EntryTS(int tipo_apuntado, String name, int kind, int blockLevel, int offset) { //para pointer(tipo)
		this.name = name;
		this.kind = kind;
		this.blockLevel = blockLevel;
		this.offset = offset;
		
		this.tipo = new ETipo_Pointer(tipo_apuntado);
	}
	
	public EntryTS(int tipo_apuntado, String name, int kind, int blockLevel) { //para pointer(tipo)
		this(tipo_apuntado, name, kind, blockLevel, 0); //offset = 0
	}*/
	
	public EntryTS(String name, int kind, int blockLevel, ETipo etipo, int offset) {
		this.name = name;
		this.kind = kind;
		this.blockLevel = blockLevel;
		this.offset = offset;
		
		this.setETipo(etipo); //para que cree nuevo y no asigne solo direccion mem
	}
	
	public EntryTS(String name, int kind, int blockLevel, ETipo etipo) {
		this(name, kind, blockLevel, etipo, 0); //offset = 0
	}
	
	//fin constructores, son muchos eh xDD

	
	public long getValue() {
		return tipo.getValue(); //no hace falta comprobar: if (tipo.getIdTipo() != Tipos.POINTER)
	}

	public void setValue(long value) {
		this.tipo.setValue(value);
	}

	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getKind() {
		return kind;
	}
	
	public void setKind(int kind) {
		this.kind = kind;
	}
	
	public int getBlockLevel() {
		return blockLevel;
	}
	
	public void setBlockLevel(int blockLevel) {
		this.blockLevel = blockLevel;
	}

	@Override
	public String toString() {
		return /*EntryTS*/ "[name=" + name + ", kind=" + getKindStr(kind) + ", blockLevel="
				+ blockLevel + ", tipo=" + Tipos.getTipoStr(tipo.getIdTipo())  
				+ ", etipo=" + tipo + ", offset=" + offset + "]"; //+ ", dir etipo=" + this.tipo
	}

	public int getTipo() {
		return tipo.getIdTipo();
	}

	public void setTipo(int tipo) {
		this.tipo.setIdTipo(tipo); //XXX: cuidado esto no deberia hacer asi, hace falta el switch
	}
	
	public ETipo getETipo() {
		return tipo;
	}

	public void setETipo(ETipo etipo) {
		switch (etipo.getIdTipo()) {
		case Tipos.INT: this.tipo = new ETipo_Int(etipo.getValue()); break;
		case Tipos.LONG: this.tipo = new ETipo_Long(etipo.getValue()); break;
		case Tipos.FLOAT: this.tipo = new ETipo_Float(etipo.getValue(), etipo.getDecimalValue()); break;
		case Tipos.POINTER: this.tipo = new ETipo_Pointer(etipo.getPuntero()); break;
		default: this.tipo = new ETipo_Int(); //por poner algo xD
		} 
	}

	//Practica 16: asignacion de memoria
	
	public int getOffset() {
		return offset;
	}

	public void setOffset(int offset) {
		this.offset = offset;
	}
	
	public int getSize() {
		return this.tipo.getSize(); // Tipos.getSize(this.tipo.getIdTipo());
	}
	
	public boolean isGlobal() { //true si es variable global
		return this.getBlockLevel() == 0;
	}
	
	public long getDecimalValue() {
		return this.tipo.getDecimalValue(); // no hace falta comprobar: if (tipo.getIdTipo() == Tipos.FLOAT)
	}

	public void setDecimalValue(long dvalue) {
		this.tipo.setDecimalValue(dvalue); //no hace falta comprobar: if (tipo.getIdTipo() == Tipos.FLOAT)
	}
	
	public void setPuntero(ArrayList<ETipo> puntero) {
		this.tipo.setPuntero(puntero);
	}
	
	/*public void setApuntado(ETipo etipo) {
		this.tipo.setPuntero(etipo);
	}*/
	
	public ETipo getApuntado() {
		return this.tipo.getApuntado();
	}
}
